/**
 * For the license, see main.cpp file
 */

#include "Authenticator.h"
#include "Qrm3Controller.h"
#include "SettingsGlobalResource.h"

#define CONN_TIMEOUT 8000

void Authenticator::authMySelf()
{
	/* Reg Exps */
	QRegExp regExpId(".+NAME=\"ID\" VALUE=\"([^\"]+).+");
	QRegExp regExpState(".+NAME=\"STATE\" VALUE=\"([^\"]+).+");
	
	/* getting info from controller */
	Qrm3Controller *qrm3Controller = Qrm3Controller::getInstance();
	
	/* The values from Settings */
	QString *username = new QString(qrm3Controller->getSettingsExpert()->getSetting(SETTING_USERNAME).toString());
	QString *password = new QString(QByteArray::fromBase64(qrm3Controller->getSettingsExpert()->getSetting(SETTING_PASSWORD).toByteArray()));
	QString *serverIp = new QString(qrm3Controller->getSettingsExpert()->getSetting(SETTING_SERVER_IP).toString());
	quint32 serverPort = (quint32)qrm3Controller->getSettingsExpert()->getSetting(SETTING_SERVER_PORT).toUInt();
	
	/* temp params */
	QString currentId, currentState, temp;
	bool matchError = false;
						
	emit newLogLine("Starting SSL authentication.");
	
	/* start SSL stuff */
	QSslSocket socket;
	socket.connectToHostEncrypted(*serverIp, serverPort);
	
	qDebug() << "Starting SSL authentication to:" << serverIp->toUtf8() << "port" << serverPort;
	
	socket.ignoreSslErrors();
	socket.waitForEncrypted(CONN_TIMEOUT);

	socket.write("GET / HTTP/1.0\r\n\r\n");
	
	bool isConnected = socket.waitForConnected(CONN_TIMEOUT);
	qDebug() << "is connected?" << isConnected;
	
	/* not connected? */
	if(!isConnected)
	{
		//error
		emit newLogLine("Error: server unreachable or off-line.", true);
		Qrm3Controller::getInstance()->getGui()->changeTrayIcon(false);
		return;
	}
	
	/* STAGE 1 - Read state and ID */
	bool first = true;
	while (socket.waitForReadyRead(CONN_TIMEOUT))
	{
		temp.clear();
		temp = socket.readAll();
		
		/* HTTP STATE == 200? */
		if(first)
		{
			if(!temp.contains("200 OK"))
			{
				qWarning() << "Server response with a non 200 Http state.";
				// HTTP ERROR.
			}
			first = false;
		}
		
		if(regExpId.indexIn(temp) != -1)
		{
			currentId = regExpId.cap(1);
			qDebug() << "Client ID is:" << regExpId.cap(1).toUtf8();
		}
		else
			matchError = true;
		
		if(regExpState.indexIn(temp) != -1)
		{
			currentState = regExpState.cap(1);
			qDebug() << "State is:" << regExpState.cap(1).toUtf8();
		}
		else
			matchError = true;
	}
	
	/* STAGE 2 - sendig username */
	if(!matchError && currentState == "1")
	{	
		emit newLogLine("Sending username.");
		
		matchError = false;
		
		/* prepare post data */
		QByteArray post(	"ID=" + currentId.toUtf8() + "&" +
							"STATE=" + currentState.toUtf8() + "&" +
							"DATA=" + username->toUtf8());
		
		QByteArray postLength;
		postLength.setNum(post.length());
		
		/* reconnect the socket before sending http POST data */
		socket.connectToHostEncrypted(*serverIp, serverPort);
		socket.ignoreSslErrors();
		socket.waitForEncrypted(CONN_TIMEOUT);
		
		/* sending http POST data */
		socket.write("POST HTTP/1.0\r\n");
		socket.write("Content-Length: " + postLength + "\r\n");
		socket.write("Content-Type: application/x-www-form-urlencoded\r\n");
		socket.write("\r\n");
		socket.write(post + "\r\n");
		socket.flush();

		temp.clear();
		
		while (socket.waitForReadyRead(CONN_TIMEOUT))
		{
			temp += socket.readAll();
		}
		
		/* read the response and get the new state */
		if(regExpState.indexIn(temp) != -1)
		{
			currentState = regExpState.cap(1);
			qDebug() << "State is:" << regExpState.cap(1).toUtf8();
		}
		else
			matchError = true;
	}
	
	/* STAGE 3 - sendig password */
	if(!matchError && currentState == "2")
	{
		emit newLogLine("Sending password.");
		
		matchError = false;
		
		/* prepare post data */
		QByteArray post(	"ID=" + currentId.toUtf8() + "&" +
							"STATE=" + currentState.toUtf8() + "&" +
							"DATA=" + password->toUtf8());
		
		QByteArray postLength;
		postLength.setNum(post.length());
		
		/* reconnect the socket before sending http POST data */
		socket.connectToHostEncrypted(*serverIp, serverPort);
		socket.ignoreSslErrors();
		socket.waitForEncrypted(CONN_TIMEOUT);
		
		/* sending http POST data */
		socket.write("POST HTTP/1.0\r\n");
		socket.write("Content-Length: " + postLength + "\r\n");
		socket.write("Content-Type: application/x-www-form-urlencoded\r\n");
		socket.write("\r\n");
		socket.write(post + "\r\n");
		socket.flush();

		temp.clear();
		
		while (socket.waitForReadyRead(CONN_TIMEOUT))
		{
			temp += socket.readAll();
			if(temp.contains("</html>", Qt::CaseInsensitive))
				break;
		}
		
		/* read the response and get the new state */
		if(regExpState.indexIn(temp) != -1)
		{
			currentState = regExpState.cap(1);
			qDebug() << "State is:" << regExpState.cap(1).toUtf8();
		}
		else
		{
			matchError = true;
			if(temp.contains("Access denied"))
				emit newLogLine("Access denied - wrong user name or password.", true);
		}
			

	}
	
	/* STAGE final - autorize */
	if(!matchError && currentState == "3")
	{
		emit newLogLine("Getting server authorization...");
		
		matchError = false;
		
		/* prepare post data */
		QByteArray post(	"ID=" + currentId.toUtf8() + "&" +
							"STATE=3&" +
							"DATA=1");
		
		QByteArray postLength;
		postLength.setNum(post.length());
		
		/* reconnect the socket before sending http POST data */
		socket.close();
		socket.connectToHostEncrypted(*serverIp, serverPort);
		socket.ignoreSslErrors();
		socket.waitForEncrypted(CONN_TIMEOUT);
		
		/* sending http POST data */
		socket.write("POST HTTP/1.0\r\n");
		socket.write("Content-Length: " + postLength + "\r\n");
		socket.write("Content-Type: application/x-www-form-urlencoded\r\n");
		socket.write("\r\n");
		socket.write(post + "\r\n");
		socket.flush();

		temp.clear();
		
		while (socket.waitForReadyRead(CONN_TIMEOUT))
		{
			temp += socket.readAll();
		}
		
		/* read the response and get the new state */
		if(temp.contains("User authorized for standard services"))
		{
			currentState = regExpState.cap(1);
			qDebug() << "Authorized";
			
			//connected!
			emit newLogLine("Authentication accomplish!.");
			Qrm3Controller::getInstance()->getGui()->changeTrayIcon(true);	
		}
		else
		{
			//error
			emit newLogLine("Error: not authenticated.", true);
			Qrm3Controller::getInstance()->getGui()->changeTrayIcon(false);
		}
	}
	else
	{
		//error
		qDebug() << "Html parser error.";
		emit newLogLine("Error: not authenticated.", true);
	}
	

}

bool Authenticator::isConnected()
{
	bool isConnectedHost1 = false;
	bool isConnectedHost2 = false;
	QByteArray pc1, pc2;

	QTcpSocket socket1, socket2;
	socket1.connectToHost("www.google.it", 80);
	socket2.connectToHost("it.yahoo.com", 80);
	
	/**
	 * Check if google italy is reachable
	 */
	if (!socket1.waitForConnected(CONN_TIMEOUT)) 
	{
		qDebug() << socket1.errorString();
		isConnectedHost1 = false;
	}
	
	/* get http google */
	socket1.write("GET /webhp HTTP/1.1\r\n");
	socket1.write("Host: www.google.it\r\n");
	socket1.write("User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.10) Gecko/20071201 BonEcho/2.0.0.10\r\n");
	socket1.write("Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5\r\n");
	socket1.write("Accept-Charset: iso-8859-1, utf-8;q=0.5, *;q=0.5\r\n");
	socket1.write("\r\n");
	socket1.flush();
	
	/* Read http header */
	if(socket1.waitForReadyRead(CONN_TIMEOUT))
	{
		// read only a part of header HTTP (it's enought)
		pc1 = socket1.read(64);
	}
	
	qDebug() << pc1;
	
	if(pc1.contains("200 OK"))
		isConnectedHost1 = true;

	/* Close and Destroy the socket */
	socket1.close();
	
	qDebug() << "Google is:";
	(isConnectedHost1)? qDebug() << "Reachable" : qDebug() << "NOT Reachable";
		
	/**
	 * Check if yahoo italy is reachable
	 */
	if (!socket2.waitForConnected(CONN_TIMEOUT)) 
	{
		qDebug() << socket2.errorString();
		isConnectedHost2 = false;
	}
	
	/* get http yahoo */
	socket2.write("GET /index.html HTTP/1.1\r\n");
	socket2.write("Host: it.yahoo.com\r\n");
	socket2.write("User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.10) Gecko/20071201 BonEcho/2.0.0.10\r\n");
	socket2.write("Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5\r\n");
	socket2.write("Accept-Charset: iso-8859-1, utf-8;q=0.5, *;q=0.5\r\n");
	socket2.write("\r\n");
	socket2.flush();
	
	/* Read http header */
	if(socket2.waitForReadyRead(CONN_TIMEOUT))
	{
		// read only a part of header HTTP (it's enought)
		pc2 = socket2.read(64);
	}
	
	qDebug() << pc2;
	
	if(pc2.contains("200 OK"))
		isConnectedHost2 = true;

	/* Close and Destroy the socket */
	socket2.close();
	
	qDebug() << "Yahoo is:";
	(isConnectedHost2)? qDebug() << "Reachable" : qDebug() << "NOT Reachable";
		
	/* clear headers */
	pc1.clear();
	pc2.clear();
	
	return isConnectedHost1 && isConnectedHost2;
}

void Authenticator::run()
{
	qDebug() << "Authenticator thread started.";
	
	emit newLogLine(""); //line clear
	
	if(isConnected())
	{
		emit newLogLine("Connected, Authentication skipped.");
		Qrm3Controller::getInstance()->getGui()->changeTrayIcon(true);
	}
	else
	{
		emit newLogLine("NOT connected, Authentication required.");
		Qrm3Controller::getInstance()->getGui()->changeTrayIcon(false);	
		authMySelf();
	}
}
